{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第7章 支持向量机"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn.datasets import load_iris\n",
    "from sklearn.model_selection import  train_test_split\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# data\n",
    "def create_data():\n",
    "    iris = load_iris()\n",
    "    df = pd.DataFrame(iris.data, columns=iris.feature_names)\n",
    "    df['label'] = iris.target\n",
    "    df.columns = [\n",
    "        'sepal length', 'sepal width', 'petal length', 'petal width', 'label'\n",
    "    ]\n",
    "    data = np.array(df.iloc[:100, [0, 1, -1]])\n",
    "    for i in range(len(data)):\n",
    "        if data[i, -1] == 0:\n",
    "            data[i, -1] = -1\n",
    "    # print(data)\n",
    "    return data[:, :2], data[:, -1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "X, y = create_data()\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x1596679da50>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter(X[:50,0],X[:50,1], label='0')\n",
    "plt.scatter(X[50:,0],X[50:,1], label='1')\n",
    "plt.legend()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "----\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class SVM:\n",
    "    def __init__(self, max_iter=100, kernel='linear'):\n",
    "        self.max_iter = max_iter\n",
    "        self._kernel = kernel\n",
    "\n",
    "    def init_args(self, features, labels):\n",
    "        self.m, self.n = features.shape\n",
    "        self.X = features\n",
    "        self.Y = labels\n",
    "        self.b = 0.0\n",
    "\n",
    "        # 将Ei保存在一个列表里\n",
    "        self.alpha = np.ones(self.m)\n",
    "        self.E = [self._E(i) for i in range(self.m)]\n",
    "        # 松弛变量\n",
    "        self.C = 1.0\n",
    "\n",
    "    def _KKT(self, i):\n",
    "        y_g = self._g(i) * self.Y[i]\n",
    "        if self.alpha[i] == 0:\n",
    "            return y_g >= 1\n",
    "        elif 0 < self.alpha[i] < self.C:\n",
    "            return y_g == 1\n",
    "        else:\n",
    "            return y_g <= 1\n",
    "\n",
    "    # g(x)预测值，输入xi（X[i]）\n",
    "    def _g(self, i):\n",
    "        r = self.b\n",
    "        for j in range(self.m):\n",
    "            r += self.alpha[j] * self.Y[j] * self.kernel(self.X[i], self.X[j])\n",
    "        return r\n",
    "\n",
    "    # 核函数\n",
    "    def kernel(self, x1, x2):\n",
    "        if self._kernel == 'linear':\n",
    "            return sum([x1[k] * x2[k] for k in range(self.n)])\n",
    "        elif self._kernel == 'poly':\n",
    "            return (sum([x1[k] * x2[k] for k in range(self.n)]) + 1)**2\n",
    "\n",
    "        return 0\n",
    "\n",
    "    # E（x）为g(x)对输入x的预测值和y的差\n",
    "    def _E(self, i):\n",
    "        return self._g(i) - self.Y[i]\n",
    "\n",
    "    def _init_alpha(self):\n",
    "        # 外层循环首先遍历所有满足0<a<C的样本点，检验是否满足KKT\n",
    "        index_list = [i for i in range(self.m) if 0 < self.alpha[i] < self.C]\n",
    "        # 否则遍历整个训练集\n",
    "        non_satisfy_list = [i for i in range(self.m) if i not in index_list]\n",
    "        index_list.extend(non_satisfy_list)\n",
    "\n",
    "        for i in index_list:\n",
    "            if self._KKT(i):\n",
    "                continue\n",
    "\n",
    "            E1 = self.E[i]\n",
    "            # 如果E2是+，选择最小的；如果E2是负的，选择最大的\n",
    "            if E1 >= 0:\n",
    "                j = min(range(self.m), key=lambda x: self.E[x])\n",
    "            else:\n",
    "                j = max(range(self.m), key=lambda x: self.E[x])\n",
    "            return i, j\n",
    "\n",
    "    def _compare(self, _alpha, L, H):\n",
    "        if _alpha > H:\n",
    "            return H\n",
    "        elif _alpha < L:\n",
    "            return L\n",
    "        else:\n",
    "            return _alpha\n",
    "\n",
    "    def fit(self, features, labels):\n",
    "        self.init_args(features, labels)\n",
    "\n",
    "        for t in range(self.max_iter):\n",
    "            # train\n",
    "            i1, i2 = self._init_alpha()\n",
    "\n",
    "            # 边界\n",
    "            if self.Y[i1] == self.Y[i2]:\n",
    "                L = max(0, self.alpha[i1] + self.alpha[i2] - self.C)\n",
    "                H = min(self.C, self.alpha[i1] + self.alpha[i2])\n",
    "            else:\n",
    "                L = max(0, self.alpha[i2] - self.alpha[i1])\n",
    "                H = min(self.C, self.C + self.alpha[i2] - self.alpha[i1])\n",
    "\n",
    "            E1 = self.E[i1]\n",
    "            E2 = self.E[i2]\n",
    "            # eta=K11+K22-2K12\n",
    "            eta = self.kernel(self.X[i1], self.X[i1]) + self.kernel(\n",
    "                self.X[i2],\n",
    "                self.X[i2]) - 2 * self.kernel(self.X[i1], self.X[i2])\n",
    "            if eta <= 0:\n",
    "                # print('eta <= 0')\n",
    "                continue\n",
    "\n",
    "            alpha2_new_unc = self.alpha[i2] + self.Y[i2] * (\n",
    "                E1 - E2) / eta  #此处有修改，根据书上应该是E1 - E2，书上130-131页\n",
    "            alpha2_new = self._compare(alpha2_new_unc, L, H)\n",
    "\n",
    "            alpha1_new = self.alpha[i1] + self.Y[i1] * self.Y[i2] * (\n",
    "                self.alpha[i2] - alpha2_new)\n",
    "\n",
    "            b1_new = -E1 - self.Y[i1] * self.kernel(self.X[i1], self.X[i1]) * (\n",
    "                alpha1_new - self.alpha[i1]) - self.Y[i2] * self.kernel(\n",
    "                    self.X[i2],\n",
    "                    self.X[i1]) * (alpha2_new - self.alpha[i2]) + self.b\n",
    "            b2_new = -E2 - self.Y[i1] * self.kernel(self.X[i1], self.X[i2]) * (\n",
    "                alpha1_new - self.alpha[i1]) - self.Y[i2] * self.kernel(\n",
    "                    self.X[i2],\n",
    "                    self.X[i2]) * (alpha2_new - self.alpha[i2]) + self.b\n",
    "\n",
    "            if 0 < alpha1_new < self.C:\n",
    "                b_new = b1_new\n",
    "            elif 0 < alpha2_new < self.C:\n",
    "                b_new = b2_new\n",
    "            else:\n",
    "                # 选择中点\n",
    "                b_new = (b1_new + b2_new) / 2\n",
    "\n",
    "            # 更新参数\n",
    "            self.alpha[i1] = alpha1_new\n",
    "            self.alpha[i2] = alpha2_new\n",
    "            self.b = b_new\n",
    "\n",
    "            self.E[i1] = self._E(i1)\n",
    "            self.E[i2] = self._E(i2)\n",
    "        return 'train done!'\n",
    "\n",
    "    def predict(self, data):\n",
    "        r = self.b\n",
    "        for i in range(self.m):\n",
    "            r += self.alpha[i] * self.Y[i] * self.kernel(data, self.X[i])\n",
    "\n",
    "        return 1 if r > 0 else -1\n",
    "\n",
    "    def score(self, X_test, y_test):\n",
    "        right_count = 0\n",
    "        for i in range(len(X_test)):\n",
    "            result = self.predict(X_test[i])\n",
    "            if result == y_test[i]:\n",
    "                right_count += 1\n",
    "        return right_count / len(X_test)\n",
    "\n",
    "    def _weight(self):\n",
    "        # linear model\n",
    "        yx = self.Y.reshape(-1, 1) * self.X\n",
    "        self.w = np.dot(yx.T, self.alpha)\n",
    "        return self.w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "svm = SVM(max_iter=200)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'train done!'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "svm.fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.64"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "svm.score(X_test, y_test)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### scikit-learn实例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-1 {color: black;background-color: white;}#sk-container-id-1 pre{padding: 0;}#sk-container-id-1 div.sk-toggleable {background-color: white;}#sk-container-id-1 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-1 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-1 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-1 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-1 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-1 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-1 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-1 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-1 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-1 div.sk-item {position: relative;z-index: 1;}#sk-container-id-1 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-1 div.sk-item::before, #sk-container-id-1 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-1 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-1 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-1 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-1 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-1 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-1 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-1 div.sk-label-container {text-align: center;}#sk-container-id-1 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-1 div.sk-text-repr-fallback {display: none;}</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>SVC()</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label sk-toggleable__label-arrow\">SVC</label><div class=\"sk-toggleable__content\"><pre>SVC()</pre></div></div></div></div></div>"
      ],
      "text/plain": [
       "SVC()"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.svm import SVC\n",
    "clf = SVC()\n",
    "clf.fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.0"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "clf.score(X_test, y_test)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
